package ru.aslanov.schedule.server.services;

import ru.aslanov.schedule.model.*;
import ru.aslanov.schedule.server.AbstractService;
import ru.aslanov.schedule.server.AccessDeniedException;
import ru.aslanov.schedule.server.AccessManager;
import ru.aslanov.schedule.server.InputLangUtil;
import ru.aslanov.schedule.utils.ScheduleUtil;
import ru.aslanov.schedule.utils.XMLUtil;

import javax.jdo.PersistenceManager;
import javax.servlet.http.HttpServletRequest;
import javax.xml.datatype.XMLGregorianCalendar;
import java.text.DateFormat;
import java.util.*;
import java.util.logging.Logger;

/**
 * @author Sergey Aslanov
 *         Created: 1/27/11 6:19 PM
 */
public class CalendarEventsService extends AbstractService {
    private static final Logger log = Logger.getLogger(CalendarEventsService.class.getName());

    @Override
    protected Class getEntityClass() {
        throw new UnsupportedOperationException();
    }

    @Override
    protected Object doFetch(HttpServletRequest request) throws Exception {
        final PersistenceManager pm = getPersistanceManager();

        final String locationKey = request.getParameter("locationKey");
        final String teacherKey = request.getParameter("teacherKey");

        Collection groups;
        String defaultInputLang = null;
        if (locationKey != null) {
            final Location location = pm.getObjectById(Location.class, locationKey);
            final String scheduleKey = location.getSchedule().getEncodedKey();
            if (!AccessManager.getInstance().hasAccessToSchedule(scheduleKey, Operation.VIEW))
                throw new AccessDeniedException(request);

            groups = (Collection) pm.newQuery(Group.class, "locationKey == :loc").execute(locationKey);
            log.fine("Found " + groups.size() + " groups for location " + location.getName());
            defaultInputLang = location.getSchedule().getDefaultInputLanguage();
        } else if (teacherKey != null) {
            final Teacher teacher = pm.getObjectById(Teacher.class, teacherKey);
            final String scheduleKey = teacher.getSchedule().getEncodedKey();
            if (!AccessManager.getInstance().hasAccessToSchedule(scheduleKey, Operation.VIEW))
                throw new AccessDeniedException(request);

            Collection groups1 = (Collection) pm.newQuery(Group.class, "teacher1Key == :t").execute(teacherKey, teacherKey);
            Collection groups2 = (Collection) pm.newQuery(Group.class, "teacher2Key == :t").execute(teacherKey, teacherKey);
            groups = new HashSet(groups1.size() + groups2.size());
            groups.addAll(groups1);
            groups.addAll(groups2);
            log.fine("Found " + groups.size() + " groups for teacher " + teacher.getName());
            defaultInputLang = teacher.getSchedule().getDefaultInputLanguage();
        } else {
            groups = Collections.EMPTY_LIST;
        }
        InputLangUtil.setThreadLocalInputLang(request.getParameter("inputLang"), defaultInputLang);

        DataList<DataItem> items = new DataList<DataItem>();
        for (Object groupObj : groups) {
            Group group = (Group) groupObj;
            if (group.isHidden()) continue;
            final String groupName = getGroupName(group);
            final String groupDsc = getGroupDsc(group);
            for (ScheduleItem scheduleItem : group.getScheduleItems()) {
                DataItem dataItem = new DataItem();
                dataItem.setAttribute("eventId", scheduleItem.getEncodedKey());
                dataItem.setAttribute("groupKey", group.getEncodedKey());
                dataItem.setAttribute("name", groupName);
                dataItem.setAttribute("description", groupDsc);

                GregorianCalendar calendar = new GregorianCalendar(ScheduleUtil.getDefaultTimezone(), ScheduleUtil.getDefaultLocale());
                calendar.set(Calendar.DAY_OF_WEEK, scheduleItem.getDayOfWeek().getCalId());

                calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(scheduleItem.getStartTime().substring(0, 2)));
                calendar.set(Calendar.MINUTE, Integer.parseInt(scheduleItem.getStartTime().substring(3)));
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                XMLGregorianCalendar xmlGregorianCalendar = XMLUtil.DATATYPE_FACTORY.newXMLGregorianCalendar(calendar);
                xmlGregorianCalendar.setTimezone(ScheduleUtil.getDefaultTimezoneOffset());
                dataItem.setAttribute("startDate", xmlGregorianCalendar.toXMLFormat());

                calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(scheduleItem.getEndTime().substring(0, 2)));
                calendar.set(Calendar.MINUTE, Integer.parseInt(scheduleItem.getEndTime().substring(3)));
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                xmlGregorianCalendar = XMLUtil.DATATYPE_FACTORY.newXMLGregorianCalendar(calendar);
                xmlGregorianCalendar.setTimezone(ScheduleUtil.getDefaultTimezoneOffset());
                dataItem.setAttribute("endDate", xmlGregorianCalendar.toXMLFormat());

                items.addItem(dataItem);
            }
        }
        log.fine("Prepared " + items.getData().size() + " events");
        return items;
    }

    @Override
    protected String getDefaultInputLang(HttpServletRequest request) {
        return null;
    }

    private String getGroupName(Group group) {
        StringBuilder sb = new StringBuilder();
        if (group.getDance() != null)
            sb.append(group.getDance().getName());
        if (group.getLevel() != null) {
            if (sb.length() > 0) sb.append(" - ");
            sb.append(group.getLevel().getName());
        }
        if (group.getTitle() != null) {
            if (sb.length() > 0) sb.append(" ");
            sb.append(group.getTitle());
        }
        return sb.toString();
    }

    private String getGroupDsc(Group group) {
        StringBuilder sb = new StringBuilder();
        if (group.getDance() != null)
            sb.append(group.getDance().getName());
        if (group.getLevel() != null) {
            if (sb.length() > 0) sb.append(" - ");
            sb.append(group.getLevel().getName());
        }
        if (group.getTitle() != null) {
            if (sb.length() > 0) sb.append(" ");
            sb.append(group.getTitle());
        }
        if (group.getTeacher1() != null) {
            if (sb.length() > 0) sb.append(" ");
            sb.append("(");
            sb.append(group.getTeacher1().getName());
            if (group.getTeacher2() != null) {
                if (sb.length() > 0) sb.append(", ");
                sb.append(group.getTeacher2().getName());
            }
            sb.append(")");
        }
        if (group.getLocation() != null) {
            if (sb.length() > 0) sb.append(", ");
            sb.append(group.getLocation().getName());
        }
        DateFormat df = DateFormat.getDateInstance();
        if (group.getStarted() != null) {
            if (sb.length() > 0) sb.append(", ");
            sb.append(df.format(group.getStarted()));
        }
        return sb.toString();
    }

    @Override
    protected boolean checkPermission(Entity existingEntity, HttpServletRequest request, PersistenceManager pm, Operation operation) throws AccessDeniedException {
        throw new UnsupportedOperationException();
    }

    @Override
    protected void makeObjectPersistent(PersistenceManager pm, Entity object, HttpServletRequest request) {
        throw new UnsupportedOperationException();
    }
}
